#pragma once

#include <memory>
#include <type_traits>
#include <vector>

#include "utils/filesystem/filesystem.h"

#include "backend/device/txda_device.h"
#include "backend/target_properties.h"

namespace txdnn {
namespace backend {

struct ProgramImplMainCGroup;

/**
 * @brief struct Program
 *        builds program from source, initialize module.
 */
struct ProgramMainCGroup {
public:
  ProgramMainCGroup();
  ProgramMainCGroup(const fs::path& program_path, std::string params, const TargetProperties& target, const std::string& kernel_src);
  ProgramMainCGroup(const fs::path& program_path, const fs::path& bin_file);
  ProgramMainCGroup(const fs::path& program_path, const std::vector<char>& bin_file);
  ProgramMainCGroup(const fs::path& program_path, const std::vector<uint8_t>& bin_file);

  std::shared_ptr<ProgramImplMainCGroup> impl_;

  txdaModule_t getModule() const;
  fs::path getCodeObjectPathName() const;
  const std::vector<char>& getCodeObjectBlob() const;

  bool isCodeObjectInMemory() const;
  bool isCodeObjectInFile() const;
  bool isCodeObjectInTempFile() const;

  void freeCodeObjectFileStorage();
  void attachBinary(std::vector<char> binary);
  void attachBinary(fs::path binary);

  friend bool operator==(const ProgramMainCGroup& l, const ProgramMainCGroup& r) {
    return l.impl_ == r.impl_;
  }

};

} // namespace backend 
} // namespace txdnn 